home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / comm / tcp / wu_ftpd_37_21.lha / wu-ftpd / src / amiga.c < prev    next >
C/C++ Source or Header  |  1995-02-25  |  14KB  |  710 lines

  1. /*
  2.  * Amiga support routines for chroot() emulation,
  3.  * some MultiUser support routines, alarm() and
  4.  * setproctitle().
  5.  *
  6.  * © 1994 Blaz Zupan, <blaz.zupan@uni-mb.si>
  7.  * All Rights Reserved
  8.  *
  9.  */
  10.  
  11. #include <exec/memory.h>
  12. #include <devices/timer.h>
  13. #include <libraries/multiuser.h>
  14. #include <proto/multiuser.h>
  15. #include <proto/dos.h>
  16. #include <proto/exec.h>
  17. #include <proto/usergroup.h>
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <stdarg.h>
  21. #include <signal.h>
  22. #include "extensions.h"
  23. #include "config.h"
  24. #include "AmiTCP:src/netlib/netlib.h"
  25.  
  26. extern char *amigausername;
  27. extern struct muBase *muBase;
  28.  
  29. /*
  30.  * This routine is an attempt to emulate the Unix chroot()
  31.  * function. It only saves the name supplied in the global
  32.  * AmigaRootDir. Everything else must be done by CheckAccess().
  33.  */
  34. extern int anonymous, guest;
  35. char AmigaRootDir[MAXPATHLEN + 2] = "";
  36.  
  37. int
  38. chroot (char *dir)
  39. {
  40.   BPTR lock;
  41.  
  42.   if (lock = Lock (dir, SHARED_LOCK))
  43.   {
  44.     NameFromLock (lock, AmigaRootDir, MAXPATHLEN);
  45.     UnLock (lock);
  46.     return 0;
  47.   }
  48.   return -1;
  49. }
  50.  
  51. /*
  52.  * Checks if pathname "name1" is above
  53.  * "name" in directory structure.
  54.  */
  55. static BOOL
  56. IsParent (char *name1, char *name2)
  57. {
  58.   BOOL ret = 0;
  59.   BPTR l1;
  60.  
  61.   if (l1 = Lock (name1, SHARED_LOCK))
  62.   {
  63.     BPTR l2;
  64.  
  65.     if (l2 = Lock (name2, SHARED_LOCK))
  66.     {
  67.       switch (SameLock (l1, l2))
  68.       {
  69.       case LOCK_DIFFERENT:
  70.     break;
  71.       case LOCK_SAME:
  72.     ret = 2;
  73.     break;
  74.       case LOCK_SAME_VOLUME:
  75.     {
  76.       BPTR l;
  77.  
  78.       while (l2)
  79.       {
  80.         l = l2;
  81.         l2 = ParentDir (l);
  82.         UnLock (l);
  83.         if (SameLock (l1, l2) == LOCK_SAME)
  84.         {
  85.           ret = 1;
  86.           break;
  87.         }
  88.       }
  89.       break;
  90.     }
  91.       }
  92.       UnLock (l2);
  93.     }
  94.     UnLock (l1);
  95.   }
  96.   return ret;
  97. }
  98.  
  99. /* Compare two strings with pattern matching */
  100. static BOOL
  101. mymatch (char *pattern, char *string)
  102. {
  103.   BOOL ret = FALSE;
  104.   char *parsedpattern;
  105.   long len = strlen (pattern) * 2 + 10;
  106.   long oldflags = DOSBase->dl_Root->rn_Flags;
  107.  
  108.   DOSBase->dl_Root->rn_Flags |= RNF_WILDSTAR;    /* turn on recognitions of star as wildcard */
  109.   if (parsedpattern = malloc (len))
  110.   {
  111.     if (ParsePattern (pattern, parsedpattern, len) != -1)
  112.       ret = MatchPattern (parsedpattern, string);
  113.     free (parsedpattern);
  114.   }
  115.   DOSBase->dl_Root->rn_Flags = oldflags;    /* restore original flags */
  116.   return ret;
  117. }
  118.  
  119. /* Checks if user is allowed to access file/directory.
  120.  * If create == TRUE check for parent of specified name
  121.  * (this is used if we want to check if user is allowed
  122.  * to access the directory into which a file should be
  123.  * created - so no "put <something> AmiTCP:db/passwd"
  124.  * hacks are possible).
  125.  */
  126. BOOL
  127. CheckAccess (char *dir, BOOL create)
  128. {
  129.   BPTR lock;
  130.   char name[MAXPATHLEN];
  131.   struct aclmember *entry = NULL;
  132.  
  133.   strcpy (name, dir);
  134.   lock = Lock (name, SHARED_LOCK);
  135.   if (!lock && create)
  136.   {
  137.     *(FilePart (name)) = 0;
  138.     lock = Lock (name, SHARED_LOCK);
  139.   }
  140.  
  141.   if (lock)
  142.     UnLock (lock);
  143.   else
  144.     /* If we could not access file/directory then return "OK"
  145.      * for now because access will be denied later by the
  146.      * command that called us.
  147.      */
  148.     return TRUE;
  149.  
  150.  
  151.   /* first check if directory is on "deny" list */
  152.   while (getaclentry ("denydir", &entry) && ARG0 && ARG1)
  153.   {
  154.     if (mymatch (ARG1, amigausername) && IsParent (ARG0, name))
  155.       return FALSE;
  156.   }
  157.   /* now see if it is under root dir */
  158.   if (IsParent (AmigaRootDir, name))
  159.     return TRUE;
  160.   /* check if access is allowed even if dir is not under root */
  161.   else
  162.   {
  163.     entry = NULL;
  164.     while (getaclentry ("allowdir", &entry) && ARG0 && ARG1)
  165.     {
  166.       if (mymatch (ARG1, amigausername) && IsParent (ARG0, name))
  167.     return TRUE;
  168.     }
  169.   }
  170.   /* If directory is not on deny or allow list and not
  171.    * under root directory then we allow access for
  172.    * real users and don't allow access for guests.
  173.    */
  174.   if (!anonymous && !guest)
  175.     return TRUE;
  176.   else
  177.     return FALSE;
  178. }
  179.  
  180. /*
  181.  * Simulate Unix geteuid() call with MultiUser.
  182.  */
  183. int
  184. amiga_geteuid (void)
  185. {
  186.   if (muBase)
  187.     return ((muGetTaskOwner (FindTask (NULL)) & muMASK_UID) >> 16);
  188.   else
  189. #undef geteuid
  190.     return (geteuid ());
  191. }
  192.  
  193. /*
  194.  * Simulate Unix seteuid() call with MultiUser.
  195.  * You have to be logged in as root initially for this
  196.  * routine to work (after that it correctly keeps track
  197.  * of the user).
  198.  */
  199. int
  200. amiga_seteuid (int u)
  201. {
  202.   if (muBase)
  203.   {
  204.     ULONG tags[5];
  205.     int res = -1;
  206.  
  207.     if (u == 0)
  208.     {
  209.       int uid;
  210.  
  211.       uid = amiga_geteuid ();
  212.  
  213.       /* Are we already root? */
  214.       if (uid == muROOT_UID)
  215.     return 0;
  216.  
  217.       /* We can't set effective user ID to root
  218.        * if we are currently logged in as nobody
  219.        */
  220.       if (uid == muNOBODY_UID)
  221.     return -1;
  222.  
  223.       /* Now logout until we become either root or
  224.        * nobody. If we become nobody we fail.
  225.        */
  226.       do
  227.       {
  228.     tags[0] = muT_Quiet;
  229.     tags[1] = TRUE;
  230.     tags[2] = TAG_END;
  231.     muLogoutA (tags);
  232.     uid = amiga_geteuid ();
  233.       }
  234.       while (uid != muROOT_UID && uid != muNOBODY_UID);
  235.  
  236.       return ((uid == muROOT_UID) ? 0 : -1);
  237.     }
  238.  
  239.     /* Check if we are maybe already logged in as that user. */
  240.     if (u == amiga_geteuid ())
  241.       return 0;
  242.  
  243.     /* Ok, so we are trying to login as someone else.
  244.      * first make sure that we are root. */
  245.     if (amiga_seteuid (0) != -1)
  246.     {
  247.       struct muUserInfo *ui;
  248.  
  249.       if (ui = muAllocUserInfo ())
  250.       {
  251.     ui->uid = u;
  252.     if (muGetUserInfo (ui, muKeyType_uid))
  253.     {
  254.       tags[0] = muT_UserID;
  255.       tags[1] = (ULONG) ui->UserID;
  256.       tags[2] = muT_NoLog;
  257.       tags[3] = TRUE;
  258.       tags[4] = TAG_END;
  259.       res = (muLoginA (tags) ? 0 : -1);
  260.     }
  261.     muFreeUserInfo (ui);
  262.       }
  263.     }
  264.     return res;
  265.   }
  266.   /* MultiUser is not installed so use dummy
  267.    * usergroup.library call.
  268.    */
  269. #undef seteuid
  270.   return (seteuid (u));
  271. }
  272.  
  273. /*
  274.  * Simulate Unix seteuid() call with MultiUser.
  275.  * You have to be logged in as root initially for this
  276.  * routine to work (after that it correctly keeps track
  277.  * of the user).
  278.  */
  279. int
  280. amiga_setegid (int g)
  281. {
  282.   /* We can't set another group under
  283.    * MultiUser so we fail.
  284.    */
  285.   if (muBase)
  286.     return -1;
  287.   /* MultiUser is not installed so use dummy
  288.    * usergroup.library call.
  289.    */
  290. #undef setegid
  291.   return (setegid (g));
  292. }
  293.  
  294.  
  295. /*
  296.  * Simulate Unix getpwnam() call with MultiUser.
  297.  */
  298.  
  299. static struct passwd p;
  300. char dummypas[] = "";
  301.  
  302. struct passwd *
  303. amiga_getpwnam (char *name)
  304. {
  305.   if (muBase)
  306.   {
  307.     struct muUserInfo *ui;
  308.     BOOL ok = FALSE;
  309.  
  310.     if (ui = muAllocUserInfo ())
  311.     {
  312.       strcpy (ui->UserID, name);
  313.       if (muGetUserInfo (ui, muKeyType_UserID))
  314.       {
  315.     ok = TRUE;
  316.     p.pw_uid = ui->uid;
  317.     p.pw_gid = ui->gid;
  318.     if (p.pw_name)
  319.       free (p.pw_name);
  320.     if (p.pw_name = malloc (strlen (ui->UserID) + 1))
  321.       strcpy (p.pw_name, ui->UserID);
  322.     else
  323.       ok = FALSE;
  324.     p.pw_passwd = "";
  325.     if (p.pw_gecos)
  326.       free (p.pw_gecos);
  327.     if (p.pw_gecos = malloc (strlen (ui->UserName) + 1))
  328.       strcpy (p.pw_gecos, ui->UserName);
  329.     else
  330.       ok = FALSE;
  331.     if (p.pw_dir)
  332.       free (p.pw_dir);
  333.     if (p.pw_dir = malloc (strlen (ui->HomeDir) + 1))
  334.       strcpy (p.pw_dir, ui->HomeDir);
  335.     else
  336.       ok = FALSE;
  337.     if (p.pw_shell)
  338.       free (p.pw_shell);
  339.     if (p.pw_shell = malloc (strlen (ui->Shell) + 1))
  340.       strcpy (p.pw_shell, ui->Shell);
  341.     else
  342.       ok = FALSE;
  343.       }
  344.       muFreeUserInfo (ui);
  345.     }
  346.     if (!ok)
  347.       return (NULL);
  348.     return (&p);
  349.   }
  350. #undef getpwnam
  351.   return (getpwnam (name));
  352. }
  353.  
  354. /*
  355.  * Simulate Unix getgrnam() call with MultiUser.
  356.  */
  357.  
  358. static struct group g;
  359.  
  360. struct group *
  361. amiga_getgrnam (char *name)
  362. {
  363.   if (muBase)
  364.   {
  365.     struct muGroupInfo *gi;
  366.     BOOL ok = FALSE;
  367.  
  368.     if (gi = muAllocGroupInfo ())
  369.     {
  370.       strcpy (gi->GroupID, name);
  371.       if (muGetGroupInfo (gi, muKeyType_GroupID))
  372.       {
  373.     static char *dummy_memb = NULL;
  374.  
  375.     ok = TRUE;
  376.     g.gr_gid = gi->gid;
  377.     if (g.gr_name)
  378.       free (g.gr_name);
  379.     if (g.gr_name = malloc (strlen (gi->GroupID) + 1))
  380.       strcpy (g.gr_name, gi->GroupID);
  381.     else
  382.       ok = FALSE;
  383.     g.gr_passwd = "";
  384.     g.gr_mem = &dummy_memb;
  385.       }
  386.       muFreeGroupInfo (gi);
  387.     }
  388.     if (!ok)
  389.       return (NULL);
  390.     return (&g);
  391.   }
  392. #undef getgrnam
  393.   return (getgrnam (name));
  394. }
  395.  
  396. /*
  397.  * Simulate Unix umask() call with MultiUser.
  398.  */
  399.  
  400. const static BYTE abits[8] =
  401. {
  402.   0, 0x2, 0x5, 0x7, 0x8, 0xA, 0xD, 0xF,
  403. };
  404.  
  405. const static UBYTE ubits[16] =
  406. {
  407.   0, 2, 1, 3, 2, 2, 3, 3,
  408.   4, 6, 5, 7, 6, 6, 7, 7,
  409. };
  410.  
  411. ULONG
  412. U2A_prot (mode_t mode)
  413. {
  414.   return ((abits[mode & 7] << FIBB_OTR_DELETE) |
  415.       (abits[(mode >> 3) & 7] << FIBB_GRP_DELETE) |
  416.       (abits[(mode >> 6) & 7] ^ 0xf));
  417. }
  418.  
  419. mode_t
  420. A2U_prot (ULONG mode)
  421. {
  422.   return ((ubits[(mode ^ 0xf) & 0xf] << 6) |
  423.       (ubits[((mode ^ 0xf) >> FIBB_GRP_DELETE) & 0xf] << 3) |
  424.       (ubits[((mode ^ 0xf) >> FIBB_OTR_DELETE) & 0xf]));
  425. }
  426.  
  427. mode_t
  428. amiga_umask (mode_t m)
  429. {
  430.   if (muBase)
  431.   {
  432.     ULONG oldmask;
  433.  
  434.     oldmask = muGetDefProtection (NULL);
  435.     muSetDefProtection (muT_DefProtection, U2A_prot (m), TAG_END);
  436.     return (A2U_prot (oldmask));
  437.   }
  438. #undef umask
  439.   return (umask (m));
  440. }
  441.  
  442. mode_t
  443. amiga_getumask (void)
  444. {
  445.   if (muBase)
  446.     return (A2U_prot (muGetDefProtection (NULL)));
  447. #undef getumask
  448.   return (getumask ());
  449. }
  450.  
  451. /* Use MultiUser function to set protection flags if
  452.  * MultiUser is installed, otherwise use original SetProtection()
  453.  * command.
  454.  */
  455. int
  456. amiga_chmod (const char *path, int mode)
  457. {
  458.   if (muBase)
  459.   {
  460.     if (!muSetProtection ((STRPTR) path, U2A_prot (mode)))
  461.     {
  462.       set_errno (IoErr ());
  463.       return -1;
  464.     }
  465.     else
  466.       return 0;
  467.   }
  468.   else
  469.   {
  470.     if (!SetProtection ((STRPTR) path, U2A_prot (mode)))
  471.     {
  472.       set_errno (IoErr ());
  473.       return -1;
  474.     }
  475.     else
  476.       return 0;
  477.   }
  478. }
  479.  
  480. /* dummy stub function for compatibility with original source */
  481. FILE *
  482. ftpd_popen (char *program, char *type, int closestderr)
  483. {
  484.   if (strpbrk (program, "`><|"))
  485.     return (NULL);
  486.  
  487.   return (popen (program, type));
  488. }
  489.  
  490. /* dummy stub function for compatibility with original source */
  491. void
  492. ftpd_pclose (FILE * iop)
  493. {
  494.   pclose (iop);
  495. }
  496.  
  497. /*
  498.  * This is a stub function which is called when
  499.  * the SIGINT signal arrives. It checks if maybe
  500.  * this SIGINT is a SIGALRM and executes the
  501.  * appropriate function.
  502.  */
  503. void (*intfunc) (int) = NULL;
  504. void (*alrmfunc) (int) = NULL;
  505. BOOL isalrm = FALSE;
  506.  
  507. void
  508. amiga_sigalrm (int signum)
  509. {
  510. #undef signal
  511.   signal (SIGINT, amiga_sigalrm);
  512.   if (isalrm)            /* Did we really get a SIGALRM? */
  513.   {
  514.     isalrm = FALSE;
  515.     (*alrmfunc) (SIGALRM);    /* Yes, execute SIGALRM function */
  516.   }
  517.   else
  518.     (*intfunc) (SIGINT);    /* No, it was a standard ctrl-c */
  519. }
  520.  
  521. /*
  522.  * This is my implementation of the Unix alarm() function.
  523.  * Is kind of a hack, because when the time expires it sends
  524.  * a break signal (control-c) to itself, the break routine
  525.  * then notices that it was called from an alarm() and
  526.  * executes the proper code. A hack, but it works :-)
  527.  */
  528. struct Task *ThisTask;
  529. struct MsgPort *TimerPort = NULL;
  530. struct timerequest *TimerIO = NULL;
  531. struct Interrupt *TimerInterrupt = NULL;
  532. BOOL deviceopen = FALSE, alarmon = FALSE;
  533.  
  534. void __saveds __interrupt
  535. IntFunc (void)
  536. {
  537.   struct Message *msg;
  538.  
  539.   if ((msg = GetMsg (TimerPort)) && alarmon)
  540.   {
  541.     isalrm = TRUE;
  542.     Signal (ThisTask, SIGBREAKF_CTRL_C);
  543.   }
  544. }
  545.  
  546. void
  547. cleanup_alarm (void)
  548. {
  549.   if (TimerIO)
  550.   {
  551.     alarmon = FALSE;
  552.  
  553.     if (!CheckIO (TimerIO))
  554.     {
  555.       AbortIO (TimerIO);
  556.       WaitIO (TimerIO);
  557.     }
  558.   }
  559.   if (deviceopen)
  560.   {
  561.     CloseDevice (TimerIO);
  562.     deviceopen = FALSE;
  563.   }
  564.   if (TimerIO)
  565.   {
  566.     DeleteExtIO (TimerIO);
  567.     TimerIO = NULL;
  568.   }
  569.   if (TimerPort)
  570.   {
  571.     FreeVec (TimerPort);
  572.     TimerPort = NULL;
  573.   }
  574.   if (TimerInterrupt)
  575.   {
  576.     FreeVec (TimerInterrupt);
  577.     TimerInterrupt = NULL;
  578.   }
  579. }
  580.  
  581. int
  582. alarm (int t)
  583. {
  584.   if (t == 0)
  585.   {
  586.     alarmon = FALSE;
  587.  
  588.     /* delete previous timer request */
  589.     if (TimerIO)
  590.     {
  591.       if (!CheckIO (TimerIO))
  592.       {
  593.     AbortIO (TimerIO);
  594.     WaitIO (TimerIO);
  595.       }
  596.     }
  597.   }
  598.   else
  599.   {
  600.     ThisTask = FindTask (NULL);
  601.     if (!TimerInterrupt)
  602.     {
  603.       if (TimerInterrupt = AllocVec (sizeof (struct Interrupt), MEMF_CLEAR))
  604.       {
  605.     TimerInterrupt->is_Node.ln_Type = NT_INTERRUPT;
  606.     TimerInterrupt->is_Code = &IntFunc;
  607.       }
  608.     }
  609.  
  610.     if (TimerInterrupt && !TimerPort)
  611.     {
  612.       if (TimerPort = AllocVec (sizeof (struct MsgPort), MEMF_CLEAR))
  613.       {
  614.     TimerPort->mp_Node.ln_Type = NT_MSGPORT;
  615.     TimerPort->mp_Flags = PA_SOFTINT;    /* cause a software interrupt when signal arrives */
  616.     TimerPort->mp_SoftInt = TimerInterrupt;
  617.     NewList (&(TimerPort->mp_MsgList));
  618.       }
  619.     }
  620.  
  621.     if (TimerPort && !TimerIO)
  622.       TimerIO = (struct timerequest *) CreateExtIO (TimerPort, sizeof (struct timerequest));
  623.  
  624.     if (TimerPort && TimerIO && !deviceopen)
  625.     {
  626.       deviceopen = (!OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerIO, 0));
  627.       if (deviceopen)
  628.     atexit (cleanup_alarm);
  629.     }
  630.  
  631.     if (deviceopen)
  632.     {
  633.       alarmon = FALSE;
  634.       if (!CheckIO (TimerIO))
  635.       {
  636.     AbortIO (TimerIO);
  637.     WaitIO (TimerIO);
  638.       }
  639.       TimerIO->tr_node.io_Command = TR_ADDREQUEST;
  640.       TimerIO->tr_time.tv_secs = t;
  641.       TimerIO->tr_time.tv_micro = 0;
  642.       alarmon = TRUE;
  643.       BeginIO ((struct IORequest *) TimerIO);
  644.     }
  645.     else
  646.       cleanup_alarm ();
  647.   }
  648. }
  649.  
  650. /*
  651.  * This is a new signal() function that also knows
  652.  * about SIGALRM (it installs SIGALRM as SIGINT with
  653.  * a special handler that knows about both SIGALRM and
  654.  * SIGINT).
  655.  */
  656. void
  657.   (*amiga_signal (int signum, void (*sigfunc) (int))) (int)
  658. {
  659.   void (*oldfunc) (int) = NULL;
  660.   if (signum == SIGALRM || signum == SIGINT)
  661.   {
  662.     if (!intfunc)
  663.       intfunc = signal (SIGINT, amiga_sigalrm);
  664.  
  665.     if (signum == SIGINT)
  666.     {
  667.       oldfunc = intfunc;
  668.       intfunc = sigfunc;
  669.     }
  670.     else
  671.     {
  672.       oldfunc = alrmfunc;
  673.       alrmfunc = sigfunc;
  674.     }
  675.   }
  676.   else
  677.     return (signal (signum, sigfunc));
  678.   return oldfunc;
  679. }
  680.  
  681. #ifdef SETPROCTITLE
  682. /* Sets name of currently running program. */
  683. void
  684. setproctitle (const char *fmt,...)
  685. {
  686.   va_list args;
  687.   char *text;
  688.  
  689.   if (text = malloc (BUFSIZ))
  690.   {
  691.     char *newfmt;
  692.  
  693.     if (newfmt = malloc (strlen (fmt) + sizeof ("ftpd: ")))
  694.     {
  695.       sprintf (newfmt, "ftpd: %s", fmt);
  696.       va_start (args, fmt);
  697.       vsprintf (text, newfmt, args);
  698.       SetProgramName (text);
  699.       va_end (args);
  700.       free (newfmt);
  701.     }
  702.     else
  703.       SetProgramName ("ftpd");
  704.     free (text);
  705.   }
  706.   else
  707.     SetProgramName ("ftpd");
  708. }
  709. #endif
  710.